#pragma once
#include "windows.h"
#include "tlhelp32.h"
#include <vector>
#include <string>
#include <xstring>

static void _multibyte_to_wchar_UTF8(char const * ch, std::wstring& ret)
{
	int _strlen = strlen(ch);
	int num = MultiByteToWideChar(CP_UTF8, 0, ch, _strlen, NULL, 0);
	WCHAR *wide = new WCHAR[num + 1];
	MultiByteToWideChar(CP_UTF8, 0, ch, _strlen, wide, num);
	wide[num] = L'\0';
	ret = wide;
	delete[] wide;
}

static BOOL _select_valid_path(char const* paths, std::wstring& validPath)
{
	std::wstring wcmd;
	_multibyte_to_wchar_UTF8(paths, wcmd);

	int i = 0, start = 0;
	WCHAR split = L';';
	std::vector<std::wstring> execs;
	while (i < wcmd.length())
	{
		if (wcmd[i] == split)
		{
			if (start != i)
			{
				execs.push_back(std::wstring(wcmd.c_str() + start, wcmd.c_str() + i));
			}
			start = i + 1;
		}
		++i;
	}
	if (start < wcmd.length())
	{
		execs.push_back(std::wstring(wcmd.c_str() + start, wcmd.c_str() + wcmd.length()));
	}

	WIN32_FIND_DATAW fileData = { 0 };
	for (auto itr = execs.begin(); itr != execs.end(); ++itr)
	{
		HANDLE hFind = FindFirstFile(itr->c_str(), &fileData);
		if (INVALID_HANDLE_VALUE != hFind)
		{
			validPath = *itr;
			return true;
		}
	}
	return false;
}



class _Win_Execute_
{
	HANDLE _M_handle = nullptr;

	HANDLE _get_process_handle_by_name(LPCWSTR name)
	{
		HANDLE         hProcessSnap = NULL;
		BOOL           bRet = FALSE;
		PROCESSENTRY32 pe32 = { 0 };

		hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if (hProcessSnap == INVALID_HANDLE_VALUE)
		{
			return nullptr;
		}
		pe32.dwSize = sizeof(PROCESSENTRY32);

		if (Process32First(hProcessSnap, &pe32))
		{
			do
			{
				if (!lstrcmpi(pe32.szExeFile, name))
				{
					HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
					CloseHandle(hProcessSnap);
					return hProcess;
				}
			} while (Process32Next(hProcessSnap, &pe32));
		}
		CloseHandle(hProcessSnap);
		return nullptr;
	}

	void _get_token()
	{
		if (_M_handle)
		{
			return;
		}
		HANDLE p = _get_process_handle_by_name(L"explorer.exe");
		if (p)
		{
			OpenProcessToken(p, TOKEN_ALL_ACCESS, &_M_handle);
		}
		return;
	}

public:
	BOOL exisit(LPCWSTR name)
	{
		return _get_process_handle_by_name(name) != nullptr;
	}
	void kill(LPCWSTR name)
	{
		HANDLE p = _get_process_handle_by_name(name);
		if (p)
		{
			TerminateProcess(p, 1);
			WaitForSingleObject(p, 5000);
		}
	}

	void run(LPCWSTR cmd)
	{
		STARTUPINFO si = { 0 };
		//si.lpDesktop = L"winsta0\\default";
		si.wShowWindow = SW_SHOW;
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.cb = sizeof(STARTUPINFO);
		PROCESS_INFORMATION pi = { 0 };
		LPWSTR tmp = new WCHAR[lstrlenW(cmd)+ 1];
		wmemcpy(tmp, cmd, lstrlenW(cmd) + 1);
		auto ret = CreateProcess(nullptr, tmp, NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
		
		wprintf(L"ret=%d path:%s\n", ret, tmp);
		delete[] tmp;
	}

	void run_as_user(LPCWSTR cmd, HANDLE token = nullptr, DWORD flag = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE)
	{
		STARTUPINFO si = { 0 };
		//si.lpDesktop = L"winsta0\\default";
		si.wShowWindow = SW_SHOW;
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.cb = sizeof(STARTUPINFO);
		PROCESS_INFORMATION pi = { 0 };

		if (token)
		{
			_M_handle = token;
		}
		else
		{
			_get_token();
		}
		LPWSTR tmp = new WCHAR[lstrlenW(cmd) + 1];
		wmemcpy(tmp, cmd, lstrlenW(cmd) + 1);
		int res = CreateProcessAsUser(_M_handle, nullptr, tmp, NULL, NULL, false, flag, NULL, NULL, &si, &pi);
		printf("%d\n", res);
		delete[] tmp;
	}
};